#include "YGLogStream.h"

#include "YGSources.h"

namespace YoghurtGum
{

	void LogStream::Message::SetString(char* a_String, int32 a_Length /*= -1*/)
	{
		length = YG_STRLEN(a_String);
		msg = new char[length + 1];
		if (a_Length == -1) { YG_STRCPY(msg, length, a_String); }
		else { YG_STRNCPY(msg, length, a_String, a_Length); }
	}

	LogStream::LogStream(char* a_Format)
	{
		strcpy(m_LogLevels[0], "INFO");
		strcpy(m_LogLevels[1], "TRACE");
		strcpy(m_LogLevels[2], "ERROR");
		strcpy(m_LogLevels[3], "FATAL");

		SetFormat(a_Format);
	}

	LogStream::~LogStream()
	{

	}

	void LogStream::SetFormat( char* a_Format )
	{
		strcpy(m_Format[0], a_Format);

		for (uint32 i = 0; i < m_FunctionTotal; ++i) { if (m_Strings[i]) { delete m_Strings[i]; } }
		m_FunctionTotal = 0;

		int start = 0;
		int length = 0;
		for (uint32 i = 0; i < strlen(a_Format); i++)
		{
			if (a_Format[i] == '$')
			{
				if (length > 0)
				{
					m_Functions[m_FunctionTotal] = &WrapAddString;
					m_Strings[m_FunctionTotal] = new Message;
					m_Strings[m_FunctionTotal]->SetString(&a_Format[start], length);
					m_FunctionTotal++;
				}

				int offset = 0;

				if (!strncmp(&a_Format[i], "$lel", strlen("$lel")))
				{
					m_Functions[m_FunctionTotal] = &WrapAddErrorLevel;
					m_Strings[m_FunctionTotal] = new Message;
					m_FunctionTotal++;

					offset = strlen("$lel");
				}
				else if (!strncmp(&a_Format[i], "$lEL", strlen("$lEL")))
				{
					m_Functions[m_FunctionTotal] = &WrapAddErrorLevelCap;
					m_Strings[m_FunctionTotal] = new Message;
					m_FunctionTotal++;

					offset = strlen("$lEL");
				}
				else if (!strncmp(&a_Format[i], "$lmsg", strlen("$lmsg")))
				{						
					m_Functions[m_FunctionTotal] = &WrapAddMessage;
					m_Strings[m_FunctionTotal] = new Message;
					m_FunctionTotal++;

					offset = strlen("$lmsg");
				}

				i += offset;
				start = i;
				length = 0;
			}

			length++;
		}

		for (uint32 i = 0; i < m_FunctionTotal; i++)
		{
			m_Functions[i](this, LEVEL_INFO, "Some string", m_Strings[i]);
		}

		bool bleh = true;
		
		/*m_Functions[m_FunctionTotal] = &WrapAddErrorLevel;
		m_Strings[m_FunctionTotal] = new Message;
		m_FunctionTotal++;

		m_Functions[m_FunctionTotal] = &WrapAddString;
		m_Strings[m_FunctionTotal] = new Message;
		m_Strings[m_FunctionTotal]->SetString(" - Awesome - ");
		m_FunctionTotal++;

		m_Functions[m_FunctionTotal] = &WrapAddString;
		m_Strings[m_FunctionTotal] = new Message;
		m_Strings[m_FunctionTotal]->SetString(" - Yup, really awesome.");
		m_FunctionTotal++;

		for (uint32 i = 0; i < m_FunctionTotal; i++)
		{
			m_Functions[i](this, LEVEL_INFO, m_Strings[i]);
		}

		bool bleh = true;*/
	}

	void LogStream::Format(char* a_Message, Level a_Level)
	{
		char dated[256] = "";
		strcpy(dated, Date::Format(m_Format[a_Level]));

		memset(m_Formatted, 0, YG_LOG_SIZE);

		int start = 0;
		int length = 0;
		for (uint32 i = 0; i < strlen(dated); i++)
		{
			if (dated[i] == '$')
			{
				strncat(m_Formatted, &dated[start], length);

				int offset = 0;

				if (!strncmp(&dated[i], "$lel", strlen("$lel")))
				{
					strcat(m_Formatted, m_LogLevels[a_Level]);

					offset = strlen("$lel");
				}
				else if (!strncmp(&dated[i], "$lEL", strlen("$lEL")))
				{
					strcat(m_Formatted, m_LogLevels[a_Level]);

					offset = strlen("$lEL");
				}
				else if (!strncmp(&dated[i], "$lmsg", strlen("$lmsg")))
				{						
					strcat(m_Formatted, a_Message);

					offset = strlen("$lmsg");
				}

				i += offset;
				start = i;
				length = 0;
			}

			length++;
		}
	}

	void LogStream::AddErrorLevel(Level a_Level, char* a_Output, Message* a_String)
	{
		strcat(m_Formatted, m_LogLevels[a_Level]);
	}

	void LogStream::WrapAddErrorLevel(void* a_Target, Level a_Level, char* a_Output, Message* a_String )
	{
		LogStream* target = (LogStream*)a_Target;
		target->AddErrorLevel(a_Level, a_Output, a_String);
	}

	void LogStream::AddErrorLevelCap(Level a_Level, char* a_Output, Message* a_String)
	{
		strcat(m_Formatted, m_LogLevels[a_Level]);
	}

	void LogStream::WrapAddErrorLevelCap(void* a_Target, Level a_Level, char* a_Output, Message* a_String)
	{
		LogStream* target = (LogStream*)a_Target;
		target->AddErrorLevelCap(a_Level, a_Output, a_String);
	}

	void LogStream::AddString(Level a_Level, char* a_Output, Message* a_String)
	{
		strncat(m_Formatted, a_String->msg, a_String->length);
	}

	void LogStream::WrapAddString( void* a_Target, Level a_Level, char* a_Output, Message* a_String )
	{
		LogStream* target = (LogStream*)a_Target;
		target->AddString(a_Level, a_Output, a_String);
	}

	void LogStream::AddDate(Level a_Level, char* a_Output, Message* a_String)
	{
		strcat(m_Formatted, Date::Format(a_String->msg));
	}

	void LogStream::WrapAddDate(void* a_Target, Level a_Level, char* a_Output, Message* a_String)
	{
		LogStream* target = (LogStream*)a_Target;
		target->AddDate(a_Level, a_Output, a_String);
	}

	void LogStream::AddMessage( Level a_Level, char* a_Output, Message* a_String )
	{
		strcat(m_Formatted, a_Output);
	}

	void LogStream::WrapAddMessage( void* a_Target, Level a_Level, char* a_Output, Message* a_String )
	{
		LogStream* target = (LogStream*)a_Target;
		target->AddMessage(a_Level, a_Output, a_String);
	}

}; // namespace YoghurtGum
